home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Presentations / Presentations ’93 / Macintosh as Internet Server ƒ / inetd / TCP.cp < prev    next >
Text File  |  1993-04-27  |  6KB  |  279 lines

  1.  
  2. #include "TCP.h"
  3. #include "InetD.h"
  4.  
  5. #include <UFailure.h>
  6.  
  7. #include <Resources.h>
  8. #include <Devices.h>
  9. #include <Processes.h>
  10.  
  11. TCPListener::TCPListener(InetD* daemon)
  12. {
  13.     fDaemon        = daemon;
  14.     fBufferSize    = 0;
  15. }
  16.  
  17. TCPListener::~TCPListener()
  18. {
  19.     this->Release();
  20. }
  21.  
  22. /*    I'm assigning the result of a memory allocation directly to a
  23.     field, but its okay. The class isn't declared as a HandleObject
  24.     because I need to get at it during interrupt.
  25. */
  26. Boolean
  27. TCPListener::Initialize()
  28. {
  29.     int            numPBs;
  30.     int            i;
  31.     
  32.     Handle        resHandle;
  33.     short        theID;
  34.     ResType        theType;
  35.     Str255        theName;
  36.     
  37.     resHandle = GetResource('BUFF', 128);
  38.     FailResError();
  39.     fBufferSize = *((int*) *resHandle);
  40.     
  41.     numPBs = CountResources('TCP ');
  42.     if (numPBs > 0) {
  43.         if (!fQueue.AllocPBs(numPBs, sizeof(MyTCPiopb)))
  44.             FailNIL((void*) 0);
  45.             
  46.         for (i = 1; i <= numPBs; i++) {
  47.             resHandle = GetIndResource('TCP ', i);
  48.             FailResError();
  49.             
  50.             GetResInfo(resHandle, &theID, &theType, theName);
  51.             this->ListenOn((tcp_port) theID);
  52.             
  53.             ReleaseResource(resHandle);
  54.         }
  55.         
  56.         return true;
  57.     }
  58.     else
  59.         return false;
  60. }
  61.  
  62. void
  63. TCPListener::DoNull()
  64. {
  65.     MyTCPiopb*    pb;
  66.     short        port;
  67.     Handle        resHandle;
  68.     FailInfo    fi;
  69.     PSN            dummy;
  70.  
  71.     while ((pb = (MyTCPiopb*) fQueue.GetCompletedPB()) != nil) {
  72.         if ((pb->tcppb.csCode == TCPPassiveOpen) && (pb->tcppb.ioResult == noErr)) {
  73.             port = pb->tcppb.csParam.open.localPort;
  74.             
  75.             resHandle = GetResource('TCP ', port);
  76.             FailResError();
  77.             
  78.             HLock(resHandle);
  79.             
  80.             fDaemon->LogIt(false, "Attempting to launch %P\n", ((FSSpec*) *resHandle)->name);
  81.         
  82.             if (fi.Try()) {
  83.                 fDaemon->Launch(pb->tcppb.tcpStream, (FSSpec*) *resHandle, 'TSTR', &dummy);
  84.                 fi.Success();
  85.             }
  86.             else {
  87.                 this->CloseDown(pb);
  88.                 fDaemon->LogIt(true, "InetD:\n\nFailed to launch %P for TCP port %d\n",
  89.                                         ((FSSpec*) *resHandle)->name, port);
  90.             }
  91.  
  92.             fQueue.RecyclePB((ParmBlkPtr) pb);
  93.             
  94.             this->ListenOn(port);
  95.  
  96.             HUnlock(resHandle);        
  97.             ReleaseResource(resHandle);
  98.         }
  99.         else {
  100.             fQueue.RecyclePB((ParmBlkPtr) pb);
  101.         }
  102.     }
  103. }
  104.  
  105. void
  106. TCPListener::ListenOn(tcp_port thePort)
  107. {
  108.     MyTCPiopb*    pb        = nil;
  109.     Ptr            rcvPtr    = nil;
  110.     
  111.     rcvPtr = NewPtrSys(fBufferSize);
  112.     FailMemError();
  113.     
  114.     pb = (MyTCPiopb*) fQueue.GetUnusedPB();
  115.     FailNIL(pb);
  116.  
  117.     pb->myA5 = SetCurrentA5();
  118.     pb->listener = this;
  119.  
  120.     pb->tcppb.csCode = TCPCreate;
  121.     pb->tcppb.ioCRefNum = fDaemon->GetDriver();
  122.     pb->tcppb.csParam.create.rcvBuff = rcvPtr;
  123.     pb->tcppb.csParam.create.rcvBuffLen = fBufferSize;
  124.     pb->tcppb.csParam.create.notifyProc = &TCPNotify;
  125.     pb->tcppb.csParam.create.userDataPtr = (Ptr) this;
  126.     
  127.     FailOSErr(PBControlSync((ParmBlkPtr) pb));
  128.         
  129.     pb->tcppb.csCode = TCPPassiveOpen;
  130.     pb->tcppb.ioCRefNum = fDaemon->GetDriver();
  131.     pb->tcppb.ioCompletion = &TCPCompletion;
  132.     pb->tcppb.csParam.open.ulpTimeoutValue = 0;
  133.     pb->tcppb.csParam.open.ulpTimeoutAction = 1;
  134.     pb->tcppb.csParam.open.validityFlags = 0xC0;
  135.     pb->tcppb.csParam.open.commandTimeoutValue = 0;
  136.     pb->tcppb.csParam.open.remoteHost = 0;
  137.     pb->tcppb.csParam.open.remotePort = 0;
  138.     pb->tcppb.csParam.open.localHost = 0;
  139.     pb->tcppb.csParam.open.localPort = thePort;
  140.     pb->tcppb.csParam.open.tosFlags = 0;
  141.     pb->tcppb.csParam.open.precedence = 0;
  142.     pb->tcppb.csParam.open.dontFrag = 0;
  143.     pb->tcppb.csParam.open.timeToLive = 0;
  144.     pb->tcppb.csParam.open.security = 0;
  145.     pb->tcppb.csParam.open.optionCnt = 0;
  146.     
  147.     FailOSErr(PBControlAsync((ParmBlkPtr) pb));
  148. }
  149.  
  150. void
  151. TCPListener::CloseDown(MyTCPiopb* pb)
  152. {
  153.     pb->tcppb.csCode = TCPClose;
  154.     pb->tcppb.ioCRefNum = fDaemon->GetDriver();
  155.     pb->tcppb.csParam.close.ulpTimeoutValue = 3;
  156.     pb->tcppb.csParam.close.ulpTimeoutAction = 0;
  157.     pb->tcppb.csParam.close.validityFlags = 0xC0;
  158.     pb->tcppb.csParam.close.userDataPtr = nil;
  159.     
  160.     FailOSErr(PBControlSync((ParmBlkPtr) pb));
  161.     
  162.     pb->tcppb.csCode = TCPRelease;
  163.     pb->tcppb.csParam.create.userDataPtr = nil;
  164.     
  165.     FailOSErr(PBControlSync((ParmBlkPtr) pb));
  166.     
  167.     DisposePtr(pb->tcppb.csParam.create.rcvBuff);
  168.     FailMemError();
  169. }
  170.  
  171. /*    This actually does the Right Thing. The CQueue class is designed
  172.     specifically for handling system parameter blocks and keeps track
  173.     of them through various states of progress. The CleanQs function
  174.     only return PBs that are in use, in progress, or completed but 
  175.     awaiting processing - not unused PBs.
  176. */
  177. void
  178. TCPListener::Release()
  179. {
  180.     MyTCPiopb*    pb = nil;
  181.     
  182.     while ((pb = (MyTCPiopb*) fQueue.CleanQs()) != nil) 
  183.         this->CloseDown(pb);
  184. }
  185.  
  186. void
  187. TCPListener::NotifyMe(PSNPtr psn, StreamPtr stream, ProcPtr proc, Ptr usr)
  188. {
  189.     NoteeItem*    nu = new NoteeItem;
  190.     FailNIL(nu);
  191.  
  192.     nu->fPSN.highLongOfPSN    = psn->highLongOfPSN;
  193.     nu->fPSN.lowLongOfPSN    = psn->lowLongOfPSN;
  194.     nu->fStream                = stream;
  195.     nu->fProc                = proc;
  196.     nu->fUsrPtr                = usr;
  197.     
  198.     fNoteeList.PutOn(nu);
  199. }
  200.  
  201. /*    This currently gets called with the PSN of every app that
  202.     we launch, even the ones that don't request ASR service,
  203.     hence its okay if the notee isn't found.
  204. */
  205. void
  206. TCPListener::UnNotify(PSNPtr psn)
  207. {
  208.     NoteeItem*    old = fNoteeList.GetItem(psn);
  209.     if (old) {
  210.         fNoteeList.TakeOff(old);
  211.         delete old;
  212.     }
  213. }
  214.  
  215. NoteeItem::NoteeItem()
  216. {
  217.     fPSN.highLongOfPSN    = 0;
  218.     fPSN.lowLongOfPSN    = 0;
  219.     fStream                = nil;
  220.     fProc                = nil;
  221.     fUsrPtr                = nil;
  222. }
  223.  
  224. /*    Its okay if these don't find the item, see the comment
  225.     on the UnNotify function above.
  226. */
  227. NoteeItem*
  228. NoteeList::GetItem(PSNPtr psn)
  229. {
  230.     NoteeItem*    it = (NoteeItem*) this->First();
  231.     
  232.     while (it && (!SameProcesses(psn, &it->fPSN)))
  233.         it = (NoteeItem*) it->fNext;
  234.         
  235. //    if (it == nil) DebugStr("\pdidn't find it…");
  236.     return it;
  237. }
  238.  
  239. NoteeItem*
  240. NoteeList::GetItem(StreamPtr stream)
  241. {
  242.     NoteeItem*    it = (NoteeItem*) this->First();
  243.     
  244.     while (it && (stream != it->fStream))
  245.         it = (NoteeItem*) it->fNext;
  246.         
  247. //    if (it == nil) DebugStr("\pdidn't find it…");
  248.     return it;
  249. }
  250.  
  251. void
  252. TCPCompletion(TCPiopb* in)
  253. {
  254.     MyTCPiopb*    pb         = (MyTCPiopb*) in;
  255.     long        thisA5    = SetA5(pb->myA5);
  256.  
  257.     if (pb->tcppb.ioResult == noErr) {
  258.         pb->listener->fQueue.StoreCompletedPB((ParmBlkPtr) pb);
  259.         WakeUpProcess(&pb->listener->fDaemon->fPSN);
  260.     }
  261.  
  262.     SetA5(thisA5);
  263. }
  264.  
  265. pascal void
  266. TCPNotify(    StreamPtr stream,
  267.             unsigned short eventCode,
  268.             Ptr usr,
  269.             unsigned short termReason,
  270.             struct ICMPReport* icmp)
  271. {
  272.     NoteeItem*        them;
  273.     
  274.     them = ((TCPListener*) usr)->fNoteeList.GetItem(stream);
  275.     if (them && them->fProc) 
  276.         (*(TCPNotifyProc) them->fProc)(stream, eventCode, them->fUsrPtr, termReason, icmp);
  277. }
  278.  
  279.